// -----------------------------------------------------------------------
//  <copyright file="SpecificationEvaluator.cs" company="LiuliuSoft">
//      Copyright (c) 2022-2024 DaprPlus. All rights reserved.
//  </copyright>
//  <site>https://dapr.plus</site>
//  <last-editor>郭明锋</last-editor>
//  <last-date>2024/12/23 21:08</last-date>
// -----------------------------------------------------------------------

using DaprPlus.Authorization;
using DaprPlus.Dependency;


namespace DaprPlus.EntityFrameworkCore;

/// <summary>
/// EFCore规约执行器
/// </summary>
public class SpecificationEvaluator(IServiceProvider provider) : ISpecificationEvaluator
{
    public virtual IQueryable<T> Query<T>(IQueryable<T> source, ISpecification<T> specification) where T : class, IEntity
    {
        var query = QueryWithoutPaging(source, specification);

        if (specification.IsPagingEnabled)
        {
            query = query.Skip(specification.Skip).Take(specification.Take);
        }

        return query;
    }

    /// <summary>
    /// 执行规约查询，并返回总记录数
    /// </summary>
    /// <typeparam name="T">项类型</typeparam>
    /// <param name="source">数据源</param>
    /// <param name="specification">查询规约</param>
    /// <param name="token"></param>
    /// <returns></returns>
    public async Task<(IQueryable<T> query, int total)> QueryAsync<T>(IQueryable<T> source,
        ISpecification<T> specification, CancellationToken token = default) where T : class, IEntity
    {
        var query = QueryWithoutPaging(source, specification);
        var total = 0;

        if (specification.IsPagingEnabled)
        {
            total = await query.CountAsync(token);
            query = query.Skip(specification.Skip).Take(specification.Take);
        }

        return (query, total);
    }

    protected virtual IQueryable<T> QueryWithoutPaging<T>(IQueryable<T> source, ISpecification<T> specification) where T : class, IEntity
    {
        var query = source;

        foreach (var include in specification.Includes)
        {
            query = query.Include(include);
        }

        foreach (var includeString in specification.IncludeStrings)
        {
            query = query.Include(includeString);
        }

        if (specification.Includes.Count + specification.IncludeStrings.Count > 1)
        {
            query = query.AsSplitQuery();
        }

        query = query.Where(specification.Criteria);

        // 数据权限查询过滤
        var dataAuthService = provider.GetRequiredService<IDataAuthorizationService>();
        query = dataAuthService.ApplyDataFilters(query);

        IOrderedQueryable<T>? orderQuery = null;
        foreach (var (orderBy, isDescending) in specification.OrderExpressions)
        {
            orderQuery = orderQuery == null
                ? isDescending
                    ? query.OrderByDescending(orderBy)
                    : query.OrderBy(orderBy)
                : isDescending
                    ? orderQuery.ThenByDescending(orderBy)
                    : orderQuery.ThenBy(orderBy);
        }
        query = orderQuery ?? query;

        orderQuery = null;
        foreach (var (fieldName, isDescending) in specification.OrderStrings)
        {
            orderQuery = orderQuery == null
                ? query.OrderBy(fieldName,
                    isDescending ? ListSortDirection.Descending : ListSortDirection.Ascending)
                : orderQuery.ThenBy(fieldName,
                    isDescending ? ListSortDirection.Descending : ListSortDirection.Ascending);
        }
        query = orderQuery ?? query;
        if (specification.OrderExpressions.Count == 0 && specification.OrderStrings.Count == 0)
        {
            //无排序条件时，按默认排序
            query = query.OrderBy(m => m.Id);
        }

        return query;
    }
}
